package com.lz.ovuola.service.impl;

import java.util.Date;

import javax.annotation.Resource;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.lz.ovuola.entity.PhysiologicalBasisDo;
import com.lz.ovuola.entity.PhysiologicalEstimateDataDo;
import com.lz.ovuola.repository.mysql.impl.PhysiologicalBasisRepository;
import com.lz.ovuola.repository.mysql.impl.PhysiologicalEstimateDataRepository;
import com.lz.ovuola.service.PhysiologicalBasisService;
import com.lz.ovuola.service.assembler.PhysiologicalBasisAssembler;
import com.lz.ovuola.util.annotation.TargetDataSource;
import com.lz.ovuola.util.constant.DataSourceConsts;
import com.lz.ovuola.util.date.DateUtils;
import com.lz.ovuola.util.exception.BusinessException;
import com.lz.ovuola.util.exception.msg.PhysiologicalMsgEnum;
import com.lz.ovuola.util.response.ResponseDataPackageUtils;
import com.lz.ovuola.util.threadlocal.UserContextHolder;

/**
 * 
 * @author fz
 *
 */
@Service("physiologicalBasisService")
public class PhysiologicalBasisServiceImpl implements PhysiologicalBasisService {

	@Resource
	private PhysiologicalBasisRepository physiologicalBasisRepository;

	@Resource
	private PhysiologicalEstimateDataRepository physiologicalEstimateDataRepository;
	private static Logger logger = LoggerFactory
			.getLogger(PhysiologicalBasisServiceImpl.class);

	@TargetDataSource(DataSourceConsts.PRIMARY_DS)
	@Transactional(transactionManager = "transactionManagerDynamic", propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = false)
	@Override
	public void save(Integer physiologicalLength, Integer menstruationLength,
			Integer cycleFloatingDays, Date startTime, Integer userId) {
		if (physiologicalLength < 15 || physiologicalLength > 90)
			throw new BusinessException(
					PhysiologicalMsgEnum.PHYSIOLOGICAL_IS_WORNG.getStatus(),
					PhysiologicalMsgEnum.PHYSIOLOGICAL_IS_WORNG.getMsg());
		if (menstruationLength < 1 || menstruationLength > 14)
			throw new BusinessException(
					PhysiologicalMsgEnum.MENSTRUATION_IS_WRONG.getStatus(),
					PhysiologicalMsgEnum.MENSTRUATION_IS_WRONG.getMsg());

		if (cycleFloatingDays < 0 || cycleFloatingDays > 30)
			throw new BusinessException(
					PhysiologicalMsgEnum.CYCLE_FLOATING_DAYS_IS_WRONG
							.getStatus(),
					PhysiologicalMsgEnum.CYCLE_FLOATING_DAYS_IS_WRONG.getMsg());

		PhysiologicalBasisDo physiologicalBasisDo = physiologicalBasisRepository
				.findByUserId(userId);
		// 不存在
		Date now = new Date();
		if (physiologicalBasisDo == null) {
			if (startTime == null || DateUtils.gt(startTime, now))
				throw new BusinessException(
						PhysiologicalMsgEnum.START_TIME_IS_WRONG.getStatus(),
						PhysiologicalMsgEnum.START_TIME_IS_WRONG.getMsg());

			physiologicalBasisDo = new PhysiologicalBasisDo();
			physiologicalBasisDo.setUserId(userId);
			physiologicalBasisDo.setStartTime(startTime);
			physiologicalBasisDo.setCreateTime(now);
		}
		physiologicalBasisDo.setCycleFloatingDays(cycleFloatingDays);
		physiologicalBasisDo.setPhysiologicalLength(physiologicalLength);
		physiologicalBasisDo.setMenstruationLength(menstruationLength);
		physiologicalBasisDo.setUpdateTime(now);
		physiologicalBasisRepository.save(physiologicalBasisDo);
	}

	@TargetDataSource(DataSourceConsts.SECONDARY_DS)
	@Transactional(transactionManager = "transactionManagerDynamic", propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = true)
	@Override
	public String get(Integer userId) throws Exception {
		PhysiologicalBasisDo physiologicalBasisDo = physiologicalBasisRepository
				.findByUserId(userId);
		if (!ObjectUtils.notEqual(physiologicalBasisDo, null))
			throw new BusinessException(
					PhysiologicalMsgEnum.MEN_IS_UPLOAD.getStatus(),
					PhysiologicalMsgEnum.MEN_IS_UPLOAD.getMsg());
		return ResponseDataPackageUtils.success(PhysiologicalBasisAssembler
				.getPhysiologicalBasisAssembler().toDto(physiologicalBasisDo));
	}

	@TargetDataSource(DataSourceConsts.PRIMARY_DS)
	@Transactional(transactionManager = "transactionManagerDynamic", propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = false)
	@Override
	public void add(Date startTime, Date endTime, String menstruationDate,
			Integer userId) {
		PhysiologicalBasisDo physiologicalBasisDo = checkParams(startTime,
				endTime, menstruationDate, userId);
		physiologicalBasisDo.setStartTime(startTime);
		physiologicalBasisDo.setEndTime(endTime);
		physiologicalBasisDo.setUpdateTime(new Date());
		String menstruationHistory = physiologicalBasisDo
				.getMenstruationHistory();
		// 未上传过例假记录
		if (StringUtils.isEmpty(menstruationHistory)) {
			logger.info("用户{}尚未上传例假记录" + UserContextHolder.get().getUserId());
			physiologicalBasisDo.setMenstruationHistory(menstruationDate);
		} else {
			logger.info("用户{}上传了例假记录，记录是{}"
					+ UserContextHolder.get().getUserId(), menstruationHistory);
			physiologicalBasisDo.setMenstruationHistory(new StringBuilder()
					.append(menstruationHistory).append(",")
					.append(menstruationDate).toString());
		}
		physiologicalBasisRepository.save(physiologicalBasisDo);
	}

	@TargetDataSource(DataSourceConsts.SECONDARY_DS)
	@Transactional(transactionManager = "transactionManagerDynamic", propagation = Propagation.REQUIRED, rollbackFor = Exception.class, readOnly = true)
	@Override
	public String getMenst(Integer userId) throws Exception {
		PhysiologicalBasisDo physiologicalBasisDo = physiologicalBasisRepository
				.findByUserId(userId);
		if (!ObjectUtils.notEqual(physiologicalBasisDo, null))
			throw new BusinessException(
					PhysiologicalMsgEnum.MEN_IS_UPLOAD.getStatus(),
					PhysiologicalMsgEnum.MEN_IS_UPLOAD.getMsg());
		return ResponseDataPackageUtils.success(PhysiologicalBasisAssembler
				.getPhysiologicalBasisAssembler().toDtoMenst(
						physiologicalBasisDo));
	}

	@TargetDataSource(DataSourceConsts.PRIMARY_DS)
	@Transactional(transactionManager = "transactionManagerDynamic", propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = false)
	@Override
	public void update(Date startTime, Date endTime, String menstruationDate,
			Integer userId) {
		PhysiologicalBasisDo physiologicalBasisDo = checkParams(startTime,
				endTime, menstruationDate, userId);
		physiologicalBasisDo.setStartTime(startTime);
		physiologicalBasisDo.setEndTime(endTime);
		physiologicalBasisDo.setUpdateTime(new Date());
		physiologicalBasisDo.setMenstruationHistory(menstruationDate);
		physiologicalBasisRepository.save(physiologicalBasisDo);

		// 存在则 更新 PhysiologicalEstimateDataDo startTime
		PhysiologicalEstimateDataDo physiologicalEstimateDataDo = physiologicalEstimateDataRepository
				.findByUserIdAndStartTime(userId, startTime);
		if (ObjectUtils.notEqual(physiologicalEstimateDataDo, null)) {
			physiologicalEstimateDataDo.setStartTime(startTime);
			physiologicalEstimateDataDo.setUpdateTime(new Date());
			physiologicalEstimateDataRepository
					.save(physiologicalEstimateDataDo);
		}
	}

	/**
	 * 校验参数合法性
	 * 
	 * @param startTime
	 * @param endTime
	 * @param menstruationDate
	 * @param userId
	 * @return
	 */
	private PhysiologicalBasisDo checkParams(Date startTime, Date endTime,
			String menstruationDate, Integer userId) {
		if (DateUtils.gt(startTime, endTime))
			throw new BusinessException(
					PhysiologicalMsgEnum.START_TIME_GT_END_TIME.getStatus(),
					PhysiologicalMsgEnum.START_TIME_GT_END_TIME.getMsg());

		if (StringUtils.isEmpty(menstruationDate))
			throw new BusinessException(
					PhysiologicalMsgEnum.MEN_IS_WRONG.getStatus(),
					PhysiologicalMsgEnum.MEN_IS_WRONG.getMsg());

		PhysiologicalBasisDo physiologicalBasisDo = physiologicalBasisRepository
				.findByUserId(userId);
		if (!ObjectUtils.notEqual(physiologicalBasisDo, null))
			throw new BusinessException(
					PhysiologicalMsgEnum.MEN_IS_UPLOAD.getStatus(),
					PhysiologicalMsgEnum.MEN_IS_UPLOAD.getMsg());
		return physiologicalBasisDo;
	}

}
